package org.common.service;

import org.common.activator.Activator;
import org.common.plugin.PluginInfo;
import org.common.plugin.PluginManager;

/**
 *
 * @author gus
 */
public class ServiceRegister
{
    private PluginManager pluginManager;
    private DependenceManager dependenceManager;
    private static ServiceRegister serviceRegister = null;

    protected ServiceRegister(DependenceManager dependenceManager)
    {
        this.dependenceManager = dependenceManager;
        pluginManager = dependenceManager.<PluginManager>getBean("pluginManager");
    }

    public synchronized static ServiceRegister getInstance() throws Exception
    {
        if (serviceRegister == null)
        {
            throw new Exception("not initialezed serviceRegister");
        }
        return serviceRegister;
    }

    public synchronized static ServiceRegister getInstance(DependenceManager dependenceManager)
    {
        if (serviceRegister == null)
        {
            serviceRegister = new ServiceRegister(dependenceManager);
        }
        return serviceRegister;
    }

    public <T> T getService(Class serviceType) throws Exception
    {
        return (T)getService(serviceType, null);
    }

    public <T> T getService(Class serviceType, String pluginName) throws Exception
    {
        if (serviceType == null)
        {
            throw new IllegalArgumentException("null argumet serviceType");
        }
        ServiceProvider provider = getServiceProvider(serviceType, pluginName);
        provider.setDependencyManager(dependenceManager);
        Object obj = provider.getService();
        assert serviceType.isAssignableFrom(obj.getClass());
        return (T) obj;
    }

    public PluginInfo[] getAviablePlugins() throws Exception
    {
        return pluginManager.getPluginInfos();
    }

    private Service getServiceAnnotation(Class serviceType) throws Exception
    {
        if (!serviceType.isAnnotationPresent(Service.class))
        {
            throw new IllegalArgumentException("not a service");
        }
        return (Service) serviceType.getAnnotation(Service.class);

    }

    private ServiceProvider getServiceProvider(Class serviceType, String pluginName) throws Exception
    {
        ServiceProvider provider = null;
        Service service = getServiceAnnotation(serviceType);
        if (service.isPlugin())
        {
            provider = makeServiceProviderFromPlugin(service, pluginName);
        }
        else
        {
            provider = Activator.instance(service.serviceProvider());
        }
        return provider;
    }

    private ServiceProvider makeServiceProviderFromPlugin(Service service, String pluginName) throws Exception
    {
        assert pluginManager != null;
        PluginInfo info = getPluginInfoByName(pluginName);
        if (info == null)
        {
            throw new Exception("cannot found plugin " + service.pluginName());
        }
        return pluginManager.loadPlugin(info);
    }

    private PluginInfo getPluginInfoByName(String pluginName) throws Exception
    {
        PluginInfo info = null;
        for (PluginInfo pluginInfo : getAviablePlugins())
        {
            if (pluginInfo.getName().equalsIgnoreCase(pluginName))
            {
                info = pluginInfo;
            }
        }
        return info;
    }
}
